package cn.com.cifi.mars.bean.bo.returnCoefficient;

import cn.com.cifi.mars.bean.dto.NosTradedataDto;
import cn.com.cifi.mars.entity.SignPlanVersionSupplyDetail;
import cn.com.cifi.mars.entity.VsNosGetin;
import cn.com.cifi.mars.util.BigDecimalUtils;
import cn.com.cifi.mars.util.DateUtils;
import cn.com.cifi.mars.util.LocalDateTimeUtils;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.collections4.MapUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 回款系数明源销售数据
 * @author: JingYuanXiang
 * @date: 2020/11/12 15:08
 */
@Data
public class ReturnCoefficientNosSaleDataBO{

    @ApiModelProperty(name = "supplyDetailList", value = "供货详情列表")
    List<SignPlanVersionSupplyDetail> supplyDetailList;
    @ApiModelProperty(name = "roomList", value = "房间列表")
    List<NosTradedataDto> roomList;
    @ApiModelProperty(name = "takeBackRoomList", value = "收回全款房间列表")
    List<NosTradedataDto> takeBackRoomList;
    @ApiModelProperty(name = "receiptsList", value = "实收列表")
    List<VsNosGetin> receiptsList;
    @ApiModelProperty(name = "tolerance", value = "容差")
    BigDecimal tolerance;
    @ApiModelProperty(name = "roomTradeDateMap", value = "获取房间签约时间映射(<key:房间id,value:签约时间>)")
    Map<String, LocalDateTime> roomTradeDateMap;
    @ApiModelProperty(name = "roomAmountMap", value = "获取房间金额映射(<key:房间id,value:金额>)")
    Map<String, BigDecimal> roomAmountMap;
    @ApiModelProperty(name = "receiptsAmountMap", value = "获取实收金额映射(<key:房间id,<key:收款时间,value:金额>>)")
    Map<String, Map<String, BigDecimal>> receiptsAmountMap;

    //初始化Map
    public void initializeMap(){
        if(CollectionUtils.isNotEmpty(receiptsList)){
            //获取实收金额映射(<key:合同id,<key:收款时间,value:金额>>)
            receiptsAmountMap = receiptsList.stream().collect(
                    Collectors.groupingBy(VsNosGetin::getRoomId,
                            Collectors.toMap(s -> LocalDateTimeUtils.formatTime(s.getPayableDate(), DateUtils.DATE_JFP_STR),
                                    VsNosGetin::getPayableMoney, BigDecimal::add)));
        }
        if(CollectionUtils.isNotEmpty(roomList)){
            //获取房间金额映射(<key:房间id,value:金额>)
            roomAmountMap = roomList.stream().collect(Collectors.toMap(NosTradedataDto::getRoomId, NosTradedataDto::getTradeMoney, BigDecimal::add));
            //获取收回全款房间列表
            takeBackRoomList = roomList.stream().filter(s -> roomAmountMap.get(s.getRoomId()).subtract(getReceiptsAmountByRoomId(s.getRoomId())).compareTo(tolerance) <= 0).collect(Collectors.toList());

            //获取房间签约时间映射(<key:房间id,value:签约时间>)
            roomTradeDateMap = takeBackRoomList.stream().collect(Collectors.toMap(NosTradedataDto::getRoomId, NosTradedataDto::getTradeDate, (s1, s2) -> s1.compareTo(s2) < 0 ? s1 : s2));
            //获取房间金额映射(<key:房间id,value:金额>)
            roomAmountMap = takeBackRoomList.stream().collect(Collectors.toMap(NosTradedataDto::getRoomId, NosTradedataDto::getTradeMoney, BigDecimal::add));
        }

        if(MapUtils.isEmpty(receiptsAmountMap)){
            this.receiptsAmountMap = new HashMap<>();
        }
    }

    /**
     * 获取房间实收金额
     * @param roomId
     * @return
     */
    public BigDecimal getReceiptsAmountByRoomId(String roomId) {
        BigDecimal amount = BigDecimal.ZERO;
        if(CollectionUtils.isNotEmpty(receiptsAmountMap.get(roomId))){
            amount = receiptsAmountMap.get(roomId).entrySet().stream().map(Map.Entry::getValue).reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        return amount;
    }

    /**
     * 获取合同实收金额映射
     * @param roomId
     * @return
     */
    public Map<String, BigDecimal> getRoomReceiptsAmountMapByRoomId(String roomId) {
        return receiptsAmountMap.get(roomId);
    }

    /**
     * 获取收回全款房间id列表Map（key：标准业态编码，value：房间id列表）
     * @return
     */
    public Map<String, List<String>> getTakeBackRoomIdListByProProductCodeMap() {
        Map<String, List<String>> roomIdListByBldPrdIDMap = takeBackRoomList.stream()
                .collect(Collectors.groupingBy(NosTradedataDto::getBuildingId,
                        Collectors.mapping(NosTradedataDto::getRoomId, Collectors.toList())));

        Map<String, List<String>> roomIdListByProProductCodeMap = supplyDetailList.stream()
                .filter(s -> roomIdListByBldPrdIDMap.get(s.getOrgId()) != null)
                .collect(Collectors.toMap(SignPlanVersionSupplyDetail::getProProductCode,
                        s -> roomIdListByBldPrdIDMap.get(s.getOrgId()), (s1, s2) -> {
                            s1.addAll(s2);
                            return s1;
                        }));
        return roomIdListByProProductCodeMap;
    }

    /**
     * 获取房间id列表Map（key：标准业态编码，value：房间id列表）
     * @return
     */
    public Map<String, List<String>> getRoomIdListByProProductCodeMap() {
        Map<String, List<String>> roomIdListByBldPrdIDMap = roomList.stream()
                .collect(Collectors.groupingBy(NosTradedataDto::getBuildingId,
                        Collectors.mapping(NosTradedataDto::getRoomId, Collectors.toList())));

        Map<String, List<String>> roomIdListByProProductCodeMap = supplyDetailList.stream()
                .filter(s -> roomIdListByBldPrdIDMap.get(s.getOrgId()) != null)
                .collect(Collectors.toMap(SignPlanVersionSupplyDetail::getProProductCode,
                        s -> roomIdListByBldPrdIDMap.get(s.getOrgId()), (s1, s2) -> {
                            s1.addAll(s2);
                            return s1;
                        }));
        return roomIdListByProProductCodeMap;
    }


    /**
     * 获取标准业态已售套数Map(key:标准业态编码,value:已售套数)
     * @return
     */
    public Map<String, BigDecimal> getProProductSoldNumMap() {
        Map<String, BigDecimal> soldNumByBldPrdIDMap = roomList.stream()
                .collect(Collectors.toMap(NosTradedataDto::getBuildingId,s->s.getRoomCount(),BigDecimal::add));

        Map<String, BigDecimal> proProductSoldNumMap = supplyDetailList.stream()
                .filter(s-> null != soldNumByBldPrdIDMap.get(s.getOrgId()))
                .collect(Collectors.toMap(SignPlanVersionSupplyDetail::getProProductCode,
                        s -> soldNumByBldPrdIDMap.get(s.getOrgId()), BigDecimal::add));

        return proProductSoldNumMap;
    }

    /**
     * 获取标准业态供货套数Map(key:标准业态编码,value:供货套数)
     * @return
     */
    public Map<String, BigDecimal> getProProductSupplyNumMap() {
        Map<String, BigDecimal> proProductSupplyNumMap = supplyDetailList.stream()
                .collect(Collectors.toMap(SignPlanVersionSupplyDetail::getProProductCode,
                        s -> new BigDecimal(s.getRoomNumActual()+s.getParkingNumActual()), BigDecimal::add));

        return proProductSupplyNumMap;
    }


    /**
     * 获取标准业态回款率Map(key:标准业态，value：累计签约回款)
     * @return
     */
    public Map<String, BigDecimal> getProProductReturmRateMap() {
        //获取合同id列表Map（key：标准业态编码，value：合同id列表）
        Map<String, List<String>> roomIdListByProProductCodeMap = getRoomIdListByProProductCodeMap();
        //获取标准业态签约金额Map
        Map<String, BigDecimal> proProductContractAmountMap = roomIdListByProProductCodeMap.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, s -> {
                    List<String> roomIdList = s.getValue();
                    return roomList.stream()
                            .filter(s1 -> roomIdList.contains(s1.getRoomId()))
                            //保留签约时间小于当月的数据
                            .filter(s1 -> LocalDateTimeUtils.compareDate(s1.getTradeDate(), LocalDateTime.now(), 0))
                            .map(NosTradedataDto::getTradeMoney)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                }));
        //获取标准业态回款金额Map
        Map<String, BigDecimal> proProductReturnAmountMap = roomIdListByProProductCodeMap.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, s -> {
                    List<String> roomIdList = s.getValue();
                    return receiptsAmountMap.entrySet().stream()
                            .filter(s1 -> roomIdList.contains(s1.getKey()))
                            .flatMap(s1->s1.getValue().entrySet().stream()
                                    //保留回款时间小于当月的数据
                                    .filter(s2-> compareYearMonth(s2.getKey(),LocalDateTimeUtils.getLocalMonth(LocalDateTime.now())) <0)
                                    .map(Map.Entry::getValue)
                            ).reduce(BigDecimal.ZERO, BigDecimal::add);
                }));

        Map<String, BigDecimal> proProductReturmRateMap = proProductContractAmountMap.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, s -> BigDecimalUtils.divBigDecimal(proProductReturnAmountMap.get(s.getKey()),s.getValue(), 5)));
        return proProductReturmRateMap;
    }

    /**
     * 比较两个年月大小
     * -1 小于
     * 0 等于
     * 1 大于
     * @param yearMontA yyyy-mm
     * @param yearMonthB yyyy-mm
     * @return
     */
    private int compareYearMonth(String yearMontA, String yearMonthB) {
        String[] splitA = yearMontA.split("-");
        String[] splitB = yearMonthB.split("-");

        int yearA = Integer.parseInt(splitA[0]);
        int monthA = Integer.parseInt(splitA[1]);
        int yearB = Integer.parseInt(splitB[0]);
        int monthB = Integer.parseInt(splitB[1]);

        int compare = Integer.compare(yearA, yearB);
        if(compare == 0){
            compare = Integer.compare(monthA, monthB);
        }
        return compare;
    }

}
